package com.zc.angelica.config.mybatis.interceptor;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

@Component
@Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}))
public class AutoGenerateID implements Interceptor {


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        /**
         * 获取参数
         * */
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object param = invocation.getArgs()[1];
        /**
         * 获取请求类型
         * */
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        /**
         * 如果不是新增则结束
         * */
        if (!sqlCommandType.equals(SqlCommandType.INSERT)) {
            return invocation.proceed();
        }
        /**
         * 判断参数是否为map
         * */
        if (param instanceof Map) {
            Map paramMap = (Map) param;
            // 是否为批量插入操作
            Optional batchParam = paramMap.values().stream().filter(paramValues -> paramValues instanceof List).findFirst();
            if (batchParam.isPresent()) {
                for (Object o : (List) batchParam.get()) {
                    restId(o); // 设置id
                }
            } else {
                paramMap.put("id", snowflake.nextId()); // 设置id
            }
        } else {
            restId(param);
        }
        return invocation.proceed();
    }


    private void restId(Object param) {
        try {
            Snowflake snowflake = IdUtil.getSnowflake(1, 1);
            Field id = param.getClass().getDeclaredField("id");
            id.setAccessible(true);
            if (Objects.isNull(id.get(param))) {
                id.set(param, snowflake.nextId());
            }
        } catch (Exception e) {
        }
    }


    @Override
    public Object plugin(Object target) {
        return target instanceof Executor ? (Plugin.wrap(target, this)) : target;
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
